﻿using Microsoft.EntityFrameworkCore;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.EntityFrameworkCore;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;

namespace mozhi.smarterp.Finance.Accounts
{
    public class AccountBalanceRepository : EfCoreRepository<FinanceDbContext, AccountBalance ,Guid> , IAccountBalanceRepository
    {
        public AccountBalanceRepository(IDbContextProvider<FinanceDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }

        public async Task<AccountBalance> FindAsync(Guid id, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            var balance = await DbContext.Set<AccountBalance>().AsNoTracking().FirstOrDefaultAsync(x=>x.Id == id);

            return balance;
        }



        public async Task<List<AccountBalance>> FindAsync(AccountBalanceQuery query)
        {
            var balances = await DbContext.Set<AccountBalance>().AsNoTracking()
               .WhereIf(query.Id.HasValue, x => x.Id == query.Id)
                .WhereIf(query.Ids != null, x => query.Ids.Contains(x.Id))
                .WhereIf(query.AccountIds != null && query.AccountIds.Count > 0, x => query.AccountIds.Contains(x.AccountId))
                .WhereIf(query.CurrencyId.HasValue, x => x.CurrencyId == query.CurrencyId)
                .WhereIf(query.IncludeDimension == false, x => x.DimensionGroupValueId == null)
                .WhereIf(query.IncludeDimension == true, x => x.DimensionGroupValueId != null)
                .WhereIf(query.IncludeCurrency == true, x => x.CurrencyId != null)
                .WhereIf(query.IncludeCurrency == false, x => x.CurrencyId == null)
                .WhereIf(query.Period.HasValue, x => x.Period == query.Period)
                .WhereIf(query.StartPeriod.HasValue, x => x.Period >= query.StartPeriod)
                .WhereIf(query.EndPeriod.HasValue, x => x.Period <= query.EndPeriod)
                .OrderByDescending(x => x.AccountId).ThenBy(x => x.CurrencyId).ThenBy(x => x.DimensionGroupValueId)
                .ToListAsync();

            return balances;
        }

        public async Task<List<AccountBalance>> GetAsync(AccountBalanceQuery query)
        {
            var balances = await DbContext.Set<AccountBalance>()
                .WhereIf(query.Id.HasValue, x => x.Id == query.Id)
                .WhereIf(query.Ids != null, x => query.Ids.Contains(x.Id))
                .WhereIf(query.AccountIds != null && query.AccountIds.Count > 0, x => query.AccountIds.Contains(x.AccountId))
                .WhereIf(query.CurrencyId.HasValue, x => x.CurrencyId == query.CurrencyId)
                .WhereIf(query.IncludeDimension == false, x => x.DimensionGroupValueId == null)
                .WhereIf(query.IncludeDimension == true, x => x.DimensionGroupValueId != null)
                .WhereIf(query.IncludeCurrency == true, x => x.CurrencyId != null)
                .WhereIf(query.IncludeCurrency == false, x => x.CurrencyId == null)
                .WhereIf(query.Period.HasValue, x => x.Period == query.Period)
                .OrderByDescending(x => x.AccountId).ThenBy(x => x.CurrencyId).ThenBy(x => x.DimensionGroupValueId)
                .ToListAsync();

            return balances;
        }



        public async Task DeleteAsync(int period)
        {
            var balances = await DbContext.Set<AccountBalance>().Where(x => x.Period == period).ToListAsync();

            if (balances.Count == 0)
                return;

            await DeleteAsync(balances);
        }

        public async Task DeleteAsync(List<AccountBalance> balances)
        {
            foreach (var balance in balances)
            {
                DbContext.Set<AccountBalance>().Remove(balance);
            }

            await DbContext.SaveChangesAsync();
        }

       
        public async Task<int> GetCountAsync(AccountBalanceQuery query)
        {
            var count = await DbContext.Set<AccountBalance>().AsNoTracking()
                .WhereIf(query.Id.HasValue, x => x.Id == query.Id)
                .WhereIf(query.Ids != null, x => query.Ids.Contains(x.Id))
                .WhereIf(query.AccountIds != null && query.AccountIds.Count > 0, x => query.AccountIds.Contains(x.AccountId))
                .WhereIf(query.CurrencyId.HasValue, x => x.CurrencyId == query.CurrencyId)
                .WhereIf(query.IncludeDimension == false, x => x.DimensionGroupValueId == null)
                .WhereIf(query.IncludeDimension == true, x => x.DimensionGroupValueId != null)
                .WhereIf(query.IncludeCurrency == true, x => x.CurrencyId != null)
                .WhereIf(query.IncludeCurrency == false, x => x.CurrencyId == null)
                .WhereIf(query.Period.HasValue, x => x.Period == query.Period)
                .CountAsync();

            return count;
        }

        public async Task InsertAsync(List<AccountBalance> balances)
        {
            if (balances == null || balances.Count == 0)
                return;

            balances.ForEach(x =>
            {
                DbContext.Set<AccountBalance>().Add(x);
            });

            await DbContext.SaveChangesAsync();
        }

        public async Task UpdateAsync(List<AccountBalance> balances)
        {
            if (balances == null || balances.Count == 0)
                return;

            balances.ForEach(x =>
            {
                DbContext.Entry<AccountBalance>(x).State = EntityState.Modified;
            });

            await DbContext.SaveChangesAsync();
        }

        public async Task InsertOrUpdateAsync(List<AccountBalance> balances)
        {
            foreach (var balance in balances)
            {
                var count = DbContext.Set<AccountBalance>().AsNoTracking().Count(x => x.Id == balance.Id);
                if (count == 0)
                    DbContext.Set<AccountBalance>().Add(balance);
                else
                    DbContext.Update(balance);
            }

            await DbContext.SaveChangesAsync();
        }
    }
}
